package com.diamond.web.service;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import com.diamond.core.feature.orm.hibernate.Page;
import com.diamond.web.dto.DataTablePageDto;

/**
 * GenericService的实现类, 其他的自定义 ServiceImpl, 继承自它,可以获得常用的增删查改操作,
 * 未实现的方法有 子类各自实现
 * <p/>
 * Model : 代表数据库中的表 映射的Java对象类型
 * PK :代表对象的主键类型
 *
 * @author StarZou
 * @since 2014年6月9日 下午6:14:06
 */
@SuppressWarnings("unchecked")
public abstract class GenericService<Model,PK extends Serializable>{
	
	protected Logger log = Logger.getLogger(getClass());
	
	@Resource
	private SessionFactory sessionFactory;
	private Class<Model> clazz;
	
	public GenericService() {
		 ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();  
	     this.clazz = (Class<Model>) type.getActualTypeArguments()[0];  
	}
	
	public Session getSession() {
		Session session = sessionFactory.getCurrentSession();
		if(session==null){
			session = sessionFactory.openSession();
		}
		return session;
	}
	
	
	/**
     * 插入对象
     *
     * @param model 对象
     */
    public void insert(Model model) {
        getSession().save(model);
    }

    /**
     * 更新对象
     *
     * @param model 对象
     */
    public void update(Model model) {
        getSession().update(model);
    }

    /**
     * 通过主键, 删除对象
     *
     * @param id 主键
     */
    public void deleteById(PK id) {
    	Model m = selectById(id);
		this.delete(m);
    }

    public void delete(Model m){
    	getSession().delete(m);
    }
    
	/**
     * 通过主键, 查询对象
     *
     * @param id 主键
     * @return
     */
    public Model selectById(PK id) {
        return (Model) getSession().get(clazz, id);
    }


    public List<Model> selectList(DataTablePageDto<Model> dp) {
		String selectListHql = "from "+clazz.getSimpleName();
		initDataTablePage(dp, selectListHql);
		Query query = getSession().createQuery(selectListHql);
		List<Model> list = query.list();
	    dp.setData(list);
		return list;
    }
    
    public long totalCount(){
    	String hql = "select count(*) from "+clazz.getSimpleName();
		Long count = (Long) getSession().createQuery(hql).uniqueResult();
		return count;
    }

	public void initDataTablePage(DataTablePageDto<?> pd,
			String hql,Object ...args) {
		String hqlSelectCount = "select count(1) "+ hql.substring(hql.indexOf("from"));
		long count = (Long) createQuery(hqlSelectCount,args).uniqueResult();
		long countTotal = totalCount();
		pd.setRecordsTotal(countTotal);
		pd.setRecordsFiltered(count);
	}
    
    /**
     * @see initDataTablePage()
     * @param page
     */
    @Deprecated
	public void initPageObject(Page<Model> page) {
		String hql = "select count(*) from "+clazz.getSimpleName();
		Object obj = getSession().createQuery(hql).uniqueResult();
		Long number = Long.valueOf(obj.toString());
		page.setTotalCount(number.intValue());
	}

	public List<Model> selectList(){
    	return getSession().createQuery(
				"FROM "+clazz.getSimpleName()).
				list();
    }

	protected Query createQuery(String hql) {
		return getSession().createQuery(hql).setCacheable(true);
	}
	
	protected List<Model> findForList(String hql,Object ...args){
		return createQuery(hql,args).list();
	}
	protected Model findForObject(String hql,Object ...args){
		return (Model) createQuery(hql,args).uniqueResult();
	}
	
	protected int executeUpdate(String hql,Object ... args){
		return createQuery(hql, args).executeUpdate();
	}
	
	protected Query createQuery(String hql,Object ... args){
		Query q = createQuery(hql);
		if(args.length==1&&args[0] instanceof Object[]){
			args = (Object[]) args[0];
		}
		if(args!=null){
			int n=0;
			for (int i=0;i<args.length;i++) {
				Object arg = args[i];
				if(arg!=null){
					if(arg instanceof DataTablePageDto<?>){   //新版本分页
						DataTablePageDto<?> dt = (DataTablePageDto<?>) arg;
						
						q.setFirstResult(dt.getStart());
						q.setMaxResults(dt.getLength());
					}else if(arg instanceof Page<?>){		//旧版分页
						Page<?> page = (Page<?>) arg;
						q.setFirstResult(page.getOffset());
						q.setMaxResults(page.getPageSize());
					}else{
						q.setParameter(n++, arg);
					}
				}
			}
		}
		return q;
	}
	
}
